import * as THREE from "three"
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader.js"
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader.js"
import { STLLoader } from "three/examples/jsm/loaders/STLLoader.js"
import { TDSLoader } from "three/examples/jsm/loaders/TDSLoader.js"

/**
 * 缩略图生成器类，用于从3D模型生成缩略图
 */
export class ThumbnailGenerator {
  private renderer: THREE.WebGLRenderer | null = null;
  private scene: THREE.Scene | null = null;
  private camera: THREE.PerspectiveCamera | null = null;
  private progressCallback: ((progress: number) => void) | null = null;

  /**
   * 设置进度回调函数
   * @param callback 进度回调函数
   */
  public setProgressCallback(callback: (progress: number) => void): void {
    this.progressCallback = callback;
  }

  /**
   * 内部方法，用于触发进度更新
   * @param progress 当前进度(0-100)
   */
  private updateProgress(progress: number): void {
    if (this.progressCallback) {
      this.progressCallback(progress);
    }
  }

  /**
   * 初始化Three.js场景
   */
  public init(): void {
    // 如果已经初始化，先清理资源
    this.dispose();

    this.scene = new THREE.Scene();
    this.scene.background = new THREE.Color(0xeeeeee);

    // 相机设置（1:1比例）
    this.camera = new THREE.PerspectiveCamera(45, 1, 0.1, 1000);

    // 渲染器设置
    this.renderer = new THREE.WebGLRenderer({
      antialias: true,
      preserveDrawingBuffer: true // 允许获取图像数据
    });
    this.renderer.setSize(512, 512);
  }

  /**
   * 清理Three.js资源以防内存泄漏
   */
  public dispose(): void {
    if (this.scene) {
      // 清理场景中的物体
      this.scene.traverse((object) => {
        if (object instanceof THREE.Mesh) {
          if (object.geometry) {
            object.geometry.dispose();
          }
          if (object.material) {
            if (Array.isArray(object.material)) {
              object.material.forEach(material => material.dispose());
            } else {
              object.material.dispose();
            }
          }
        }
      });
      this.scene = null;
    }

    if (this.renderer) {
      this.renderer.dispose();
      this.renderer = null;
    }

    this.camera = null;
  }

  /**
   * 清理场景中的旧对象
   */
  private clearScene(): void {
    if (!this.scene) return;

    while(this.scene.children.length > 0) {
      this.scene.remove(this.scene.children[0]);
    }
  }

  /**
   * 根据文件扩展名获取适当的加载器
   * @param file 文件或文件路径
   * @returns 适合的加载器和类型
   */
  private getLoader(file: File | string): { loader: any, type: string } {
    // 判断是文件还是路径
    let extension = '';
    if (typeof file === 'string') {
      extension = file.toLowerCase().split('.').pop() || '';
    } else {
      extension = file.name.toLowerCase().split('.').pop() || '';
    }

    switch (extension) {
      case 'obj':
        return { loader: new OBJLoader(), type: 'obj' };
      case 'fbx':
        return { loader: new FBXLoader(), type: 'fbx' };
      case 'stl':
        return { loader: new STLLoader(), type: 'stl' };
      case '3ds':
        return { loader: new TDSLoader(), type: '3ds' };
      case 'gltf':
      case 'glb':
      default:
        return { loader: new GLTFLoader(), type: 'gltf' };
    }
  }

  /**
   * 添加基础光照到场景
   */
  private addLights(): void {
    if (!this.scene) return;

    // 添加基础光照
    this.scene.add(new THREE.AmbientLight(0xffffff, 0.8));

    // 主光源
    const light = new THREE.DirectionalLight(0xffffff, 0.5);
    light.position.set(10, 10, 10);
    this.scene.add(light);

    // 添加补充光源
    const backLight = new THREE.DirectionalLight(0xffffff, 0.3);
    backLight.position.set(-5, 5, -5);
    this.scene.add(backLight);

    // 添加底部光源，确保模型底部可见
    const bottomLight = new THREE.DirectionalLight(0xffffff, 0.2);
    bottomLight.position.set(0, -5, 0);
    this.scene.add(bottomLight);
  }

  /**
   * 设置相机视角并调整模型位置
   */
  private setupModelAndCamera(model: THREE.Object3D): void {
    if (!this.scene || !this.camera || !model) return;

    this.scene.add(model);

    // 自动调整模型位置和大小
    const bbox = new THREE.Box3().expandByObject(model);
    const center = bbox.getCenter(new THREE.Vector3());
    const size = bbox.getSize(new THREE.Vector3()).length();

    // 模型居中
    model.position.sub(center);

    // 调整相机
    this.camera.position.set(0, size * 0.5, size * 1.5);
    this.camera.lookAt(0, 0, 0);
  }

  /**
   * 渲染场景并生成缩略图
   */
  private renderThumbnail(): Promise<Blob> {
    return new Promise((resolve, reject) => {
      if (!this.renderer || !this.scene || !this.camera) {
        reject(new Error('渲染器或场景不可用'));
        return;
      }

      this.renderer.render(this.scene, this.camera);

      // 获取缩略图数据
      const canvas = this.renderer.domElement;
      canvas.toBlob((blob: Blob | null) => {
        if (blob) {
          resolve(blob);
        } else {
          reject(new Error('无法创建缩略图'));
        }
      }, 'image/png');
    });
  }

  /**
   * 从模型文件生成缩略图
   * @param modelFile 模型文件
   * @returns Promise<Blob> 缩略图Blob对象
   */
  public generateThumbnailFromFile(modelFile: File): Promise<Blob> {
    return new Promise(async (resolve, reject) => {
      if (!this.scene || !this.camera || !this.renderer) {
        this.init();
        if (!this.scene || !this.camera || !this.renderer) {
          reject(new Error('Three.js 资源初始化失败'));
          return;
        }
      }

      // 设置初始进度
      this.updateProgress(0);

      // 文件大小校验
      if (modelFile.size === 0) {
        reject(new Error('文件为空'));
        return;
      }

      // 文件大小进度权重调整
      const fileSizeWeight = Math.min(0.8, Math.max(0.2, modelFile.size / (1024 * 1024) * 0.05));
      const parseWeight = 1 - fileSizeWeight;

      // 获取文件扩展名，以确定使用哪种加载器
      const { loader, type } = this.getLoader(modelFile);
      const reader = new FileReader();

      reader.onload = async (e: any) => {
        try {
          // 清理场景中的旧对象
          this.clearScene();

          // 更新进度-文件读取完成(进度分配为总进度的fileSizeWeight部分)
          this.updateProgress(Math.round(fileSizeWeight * 100 * 0.3));

          let model: THREE.Object3D | null = null;

          // 根据模型类型选择不同的加载方法
          if (type === 'gltf') {
            // 更新进度-开始解析模型
            this.updateProgress(Math.round(fileSizeWeight * 100 * 0.5));

            // GLTF/GLB 加载
            const buffer = e.target.result;
            const gltfLoader = loader as GLTFLoader;

            // 使用parseAsync方法而不是parse，因为parseAsync是类型定义中已有的
            const gltf = await gltfLoader.parseAsync(buffer, '');
            model = gltf.scene;

            // 更新进度-模型解析完成
            this.updateProgress(Math.round(fileSizeWeight * 100));
          }
          else if (type === 'stl') {
            // 更新进度-开始解析模型
            this.updateProgress(Math.round(fileSizeWeight * 100 * 0.5));

            // STL 加载 - 返回几何体，需要创建材质和网格
            const stlLoader = loader as STLLoader;
            const geometry = await new Promise<THREE.BufferGeometry>((resolveGeometry) => {
              const result = stlLoader.parse(e.target.result);
              resolveGeometry(result);
            });

            const material = new THREE.MeshStandardMaterial({
              color: 0xaaaaaa,
              metalness: 0.25,
              roughness: 0.4
            });
            model = new THREE.Mesh(geometry, material);

            // 更新进度-模型解析完成
            this.updateProgress(Math.round(fileSizeWeight * 100));
          }
          else if (type === 'obj') {
            const objLoader = loader as OBJLoader;
            model = await new Promise<THREE.Group>((resolveModel) => {
              objLoader.parse(new TextDecoder().decode(new Uint8Array(e.target.result)), '', resolveModel);
            });
          }
          else if (type === 'fbx') {
            const fbxLoader = loader as FBXLoader;
            model = await new Promise<THREE.Group>((resolveModel) => {
              model = fbxLoader.parse(e.target.result, '');
              resolveModel(model);
            });
          }
          else if (type === '3ds') {
            const tdsLoader = loader as TDSLoader;
            model = await new Promise<THREE.Group>((resolveModel) => {
              model = tdsLoader.parse(e.target.result, '');
              resolveModel(model);
            });
          }

          if (model && this.scene) {
            // 更新进度-开始模型设置
            this.updateProgress(Math.round(fileSizeWeight * 100 + parseWeight * 100 * 0.3));

            // 设置模型和相机
            this.setupModelAndCamera(model);

            // 更新进度-模型设置完成
            this.updateProgress(Math.round(fileSizeWeight * 100 + parseWeight * 100 * 0.6));

            // 添加基础光照
            this.addLights();

            // 更新进度-场景准备完成
            this.updateProgress(Math.round(fileSizeWeight * 100 + parseWeight * 100 * 0.9));

            // 渲染缩略图
            const blob = await this.renderThumbnail();

            // 更新进度-渲染完成
            this.updateProgress(100);

            resolve(blob);
          } else {
            reject(new Error('模型加载失败'));
          }
        } catch (error) {
          console.error('从文件生成缩略图错误:', error);
          reject(error);
        }
      };

      reader.onprogress = (event) => {
        if (event.lengthComputable) {
          // 文件读取进度(只计入fileSizeWeight的一部分)
          const progress = Math.round((event.loaded / event.total) * fileSizeWeight * 100 * 0.3);
          this.updateProgress(progress);
        }
      };

      reader.onerror = (error) => {
        console.error('读取文件错误:', error);
        reject(error);
      };

      reader.readAsArrayBuffer(modelFile);
    });
  }

  /**
   * 从URL加载模型生成缩略图
   * @param url 模型URL
   * @returns Promise<Blob> 缩略图Blob对象
   */
  public generateThumbnailFromUrl(url: string): Promise<Blob> {
    return new Promise(async (resolve, reject) => {
      if (!this.scene || !this.camera || !this.renderer) {
        this.init();
        if (!this.scene || !this.camera || !this.renderer) {
          reject(new Error('Three.js 资源初始化失败'));
          return;
        }
      }

      // 设置初始进度
      this.updateProgress(0);

      try {
        // 清理场景中的旧对象
        this.clearScene();

        // 获取文件扩展名，以确定使用哪种加载器
        const { loader, type } = this.getLoader(url);
        const fullUrl = url.startsWith('/') ? `/model-api${url}` : url;

        // 网络请求权重和解析权重
        const networkWeight = 0.7; // 网络请求占70%进度
        const parseWeight = 0.3; // 解析和渲染占30%进度

        let model: THREE.Object3D | null = null;

        // 根据模型类型选择不同的加载方法
        if (type === 'gltf') {
          // GLTF/GLB 加载
          model = await new Promise<THREE.Object3D>((resolveModel, rejectModel) => {
            const gltfLoader = loader as GLTFLoader;
            gltfLoader.load(
              fullUrl,
              (gltf) => {
                // 更新进度至80%（网络请求完成，开始解析）
                this.updateProgress(Math.round(networkWeight * 100));
                resolveModel(gltf.scene);
              },
              (xhr) => {
                // 更新网络加载进度(0-70%)
                if (xhr.lengthComputable) {
                  const progress = Math.round((xhr.loaded / xhr.total) * networkWeight * 100);
                  this.updateProgress(progress);
                } else {
                  // 如果进度不可计算，给予一个模拟进度
                  const fakeProgress = Math.min(50, Math.random() * 3 + 5);
                  setTimeout(() => this.updateProgress(fakeProgress), 500);
                }
              },
              (error) => {
                console.error('GLTF加载错误:', error);
                rejectModel(error);
              }
            );
          });
        }
        else if (type === 'stl') {
          // STL 加载
          model = await new Promise<THREE.Object3D>((resolveModel, rejectModel) => {
            const stlLoader = loader as STLLoader;
            stlLoader.load(
              fullUrl,
              (geometry) => {
                // 更新进度至80%（网络请求完成，开始解析）
                this.updateProgress(Math.round(networkWeight * 100));

                const material = new THREE.MeshStandardMaterial({
                  color: 0xaaaaaa,
                  metalness: 0.25,
                  roughness: 0.4
                });
                resolveModel(new THREE.Mesh(geometry, material));
              },
              (xhr) => {
                // 更新网络加载进度(0-70%)
                if (xhr.lengthComputable) {
                  const progress = Math.round((xhr.loaded / xhr.total) * networkWeight * 100);
                  this.updateProgress(progress);
                } else {
                  // 如果进度不可计算，给予一个模拟进度
                  const fakeProgress = Math.min(50, Math.random() * 3 + 5);
                  setTimeout(() => this.updateProgress(fakeProgress), 500);
                }
              },
              (error) => {
                console.error('STL加载错误:', error);
                rejectModel(error);
              }
            );
          });
        }
        else if (type === 'obj') {
          // OBJ 加载
          model = await new Promise<THREE.Object3D>((resolveModel, rejectModel) => {
            const objLoader = loader as OBJLoader;
            objLoader.load(
              fullUrl,
              (object) => resolveModel(object),
              undefined,
              (error) => {
                console.error('OBJ加载错误:', error);
                rejectModel(error);
              }
            );
          });
        }
        else if (type === 'fbx') {
          // FBX 加载
          model = await new Promise<THREE.Object3D>((resolveModel, rejectModel) => {
            const fbxLoader = loader as FBXLoader;
            fbxLoader.load(
              fullUrl,
              (object) => resolveModel(object),
              undefined,
              (error) => {
                console.error('FBX加载错误:', error);
                rejectModel(error);
              }
            );
          });
        }
        else if (type === '3ds') {
          // 3DS 加载
          model = await new Promise<THREE.Object3D>((resolveModel, rejectModel) => {
            const tdsLoader = loader as TDSLoader;
            tdsLoader.load(
              fullUrl,
              (object) => resolveModel(object),
              undefined,
              (error) => {
                console.error('3DS加载错误:', error);
                rejectModel(error);
              }
            );
          });
        }

        if (model) {
          // 更新进度-开始模型设置
          this.updateProgress(Math.round(networkWeight * 100 + parseWeight * 100 * 0.3));

          // 设置模型和相机
          this.setupModelAndCamera(model);

          // 更新进度-模型设置完成
          this.updateProgress(Math.round(networkWeight * 100 + parseWeight * 100 * 0.6));

          // 添加基础光照
          this.addLights();

          // 更新进度-场景准备完成
          this.updateProgress(Math.round(networkWeight * 100 + parseWeight * 100 * 0.9));

          // 渲染缩略图
          const blob = await this.renderThumbnail();

          // 更新进度-渲染完成
          this.updateProgress(100);

          resolve(blob);
        } else {
          reject(new Error('模型加载失败'));
        }
      } catch (error) {
        console.error('从URL生成缩略图错误:', error);
        reject(error);
      }
    });
  }

  /**
   * 统一的接口来生成缩略图，会根据传入参数类型自动选择合适的方法
   * @param source 文件或URL
   * @returns Promise<Blob> 缩略图Blob对象
   */
  public createThumbnail(source: File | string): Promise<Blob> {
    if (!source) {
      return Promise.reject(new Error('未提供有效的源'));
    }

    // 根据源类型选择适当的生成方法
    if (typeof source === 'string') {
      // 从URL生成缩略图
      return this.generateThumbnailFromUrl(source);
    } else {
      // 从文件生成缩略图
      return this.generateThumbnailFromFile(source);
    }
  }
}

// 创建并导出一个单例实例，方便直接使用
export const thumbnailGenerator = new ThumbnailGenerator();

// 保留原始函数，同时添加带进度的新函数
export const generateThumbnailFromFile = (file: File): Promise<Blob> => {
  return thumbnailGenerator.generateThumbnailFromFile(file);
};

export const generateThumbnailFromUrl = (url: string): Promise<Blob> => {
  return thumbnailGenerator.generateThumbnailFromUrl(url);
};

export const createThumbnail = (source: File | string): Promise<Blob> => {
  return thumbnailGenerator.createThumbnail(source);
};

// 导出带进度回调的便捷函数
export const generateThumbnailFromFileWithProgress = (file: File, progressCallback?: (progress: number) => void): Promise<Blob> => {
  if (progressCallback) {
    thumbnailGenerator.setProgressCallback(progressCallback);
  }
  return thumbnailGenerator.generateThumbnailFromFile(file);
};

export const generateThumbnailFromUrlWithProgress = (url: string, progressCallback?: (progress: number) => void): Promise<Blob> => {
  if (progressCallback) {
    thumbnailGenerator.setProgressCallback(progressCallback);
  }
  return thumbnailGenerator.generateThumbnailFromUrl(url);
};

export const createThumbnailWithProgress = (source: File | string, progressCallback?: (progress: number) => void): Promise<Blob> => {
  if (progressCallback) {
    thumbnailGenerator.setProgressCallback(progressCallback);
  }
  return thumbnailGenerator.createThumbnail(source);
};
